/***********************************************************************

	This file is part of KEEL-software, the Data Mining tool for regression, 
	classification, clustering, pattern mining and so on.

	Copyright (C) 2004-2010
	
	F. Herrera (herrera@decsai.ugr.es)
    L. Sánchez (luciano@uniovi.es)
    J. Alcalá-Fdez (jalcala@decsai.ugr.es)
    S. García (sglopez@ujaen.es)
    A. Fernández (alberto.fernandez@ujaen.es)
    J. Luengo (julianlm@decsai.ugr.es)

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see http://www.gnu.org/licenses/
  
**********************************************************************/

package keel.Algorithms.Neural_Networks.NNEP_Common.neuralnet;

import java.util.ArrayList;

import javolution.xml.XmlElement;
import javolution.xml.XmlFormat;

import org.apache.commons.lang.builder.HashCodeBuilder;

/**
 * <p> Input layer of a neural net
 * @author Written by Pedro Antonio Gutierrez Penya, Aaron Ruiz Mora (University of Cordoba) 17/07/2007
 * @version 0.1
 * @since JDK1.5
 * </p>
 */

public class InputLayer implements ILayer<InputNeuron>{
	
	/**
	 * <p>
	 * Input layer of a neural net
	 * </p>
	 */
	
    /////////////////////////////////////////////////////////////////
    // ------------------------------------- Marshal/unmarshal format
    /////////////////////////////////////////////////////////////////

	/**
	 * <p>
	 * Marshal/Unmarshal maximum number of neurons and each neuron
	 * </p>
	 */
	protected static final javolution.xml.XmlFormat<InputLayer> XML = 
		new XmlFormat<InputLayer>(InputLayer.class) 
		{
			public void format(InputLayer source, XmlElement xml) 
			{
				// Marshal maxnofneurons
				xml.setAttribute("max-n-of-neurons", source.maxnofneurons);
				// Marshal each neuron
				xml.add(source.neurons, "neurons");
			}

			public InputLayer parse(XmlElement xml) 
			{
				// Resulting object
				InputLayer result = (InputLayer) xml.object();
				// Unmarshal maxnofneurons
				result.maxnofneurons = xml.getAttribute("max-n-of-neurons", 1);
				// Unmarshal each neuron
				result.neurons = xml.<ArrayList<InputNeuron>>get("neurons");
				// Return result
				return result;
			}

			public String defaultName() 
			{
				return "input-layer";
			}
		};
		
	/////////////////////////////////////////////////////////////////
	// --------------------------------------- Serialization constant
	/////////////////////////////////////////////////////////////////
	
	/** Generated by Eclipse */
	
	private static final long serialVersionUID = -4960947669851010992L;
	
	/////////////////////////////////////////////////////////////////
	// --------------------------------------------------- Attributes
	/////////////////////////////////////////////////////////////////

	/** Maximum number of neurons */
    
    protected int maxnofneurons;
    
	/** Array of neurons of the layer */
	
	protected ArrayList<InputNeuron> neurons = new ArrayList<InputNeuron>();
	
	/////////////////////////////////////////////////////////////////
	// ------------------------------------------------- Constructors
	/////////////////////////////////////////////////////////////////
	
	/**
	 * Empty constructor
	 */
	
	public InputLayer() 
	{
		super();
	}
	
	/////////////////////////////////////////////////////////////////
	// -------------------------------- Implementing ILayer interface
	/////////////////////////////////////////////////////////////////
    
	/**
	 * <p>
	 * Returns the maximum number of neurons of this layer
	 * </p>
	 * @return int Maximum number of neurons
	 */
    public int getMaxnofneurons() {
        return maxnofneurons;
    }
    
    /**
     * <p>
	 * Sets the maximum number of neurons of this layer
	 * </p>
	 * @param maxnofneurons Number of neurons
	 */
    public void setMaxnofneurons(int maxnofneurons) {
        this.maxnofneurons = maxnofneurons;
        
        //Remove the neurons
        if(neurons!=null)
            neurons.clear();
        
        //Generate the neurons
        for(int i=0; i<maxnofneurons; i++){
            InputNeuron iNeuron = new InputNeuron();
            iNeuron.setIndex(i);
            addNeuron(iNeuron);
        }
    }
    
    /**
     * <p>
	 * Add a neuron to the layer
	 * </p>
	 * @param neuron New neuron to add to the layer
	 */
    public void addNeuron(InputNeuron neuron) {
    	neurons.add(neuron);
    }
    
    /**
     * <p>
	 * Returns a neuron of the layer using its index
	 * </p>
	 * @param index Index of the neuron
	 * @return InputNeuron Neuron of the layer
	 */
    public InputNeuron getNeuron(int index) {
        return neurons.get(index);
    }
    
    /**
     * <p>
	 * Returns the number of neurons of this layer
	 * </p>
	 * @return int Number of neurons
	 */
    public int getNofneurons() {
        return neurons.size();
    }
    
    /**
     * <p>
	 * Returns the index of a neuron in the layer
	 * </p>
	 * @param neuron Neuron in the layer
	 * @return int Index of the neuron
	 */
    public int indexOf(InputNeuron neuron){
    	return neurons.indexOf(neuron);
    }
    
    /**
     * <p>
	 * Checks if this layer is equal to another
	 * </p>
	 * @param other Other layer to compare
	 * @return true if both layers are equal
	 */
    public boolean equals(ILayer<InputNeuron> other){
        if(this.hashCode()!=other.hashCode())
            return false;
        else
            return true;
    }
    
    /**
     * <p>
	 * Returns an integer number that identifies the layer
	 * </p>
	 * @return int Hashcode
	 */
    public int hashCode(){
        HashCodeBuilder hcb = new HashCodeBuilder(41, 43);
        for(INeuron neuron:neurons)
            hcb.append(neuron);
        return hcb.toHashCode();
    }
	
	/////////////////////////////////////////////////////////////////
	// ----------------------------------------------- Public methods
	/////////////////////////////////////////////////////////////////
    
    /**
     * <p>
     * Returns a copy of this input layer
     * </p>
     * @return InputLayer Copy of this input layer
     */
    public InputLayer copy(){
    	
    	// Copy result
    	InputLayer result = new InputLayer();
    	
    	// Set max of neurons 
    	result.setMaxnofneurons(this.maxnofneurons);
    	
    	// Return result
    	return result;
    }
    
}

